﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
//using System.Diagnostics;

namespace VentAnalyServer.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class StreamController : ControllerBase
    {
        // logger
        private readonly ILogger<StreamController> _logger;
        // http client factory
        private IHttpClientFactory _httpClientFactory;

        // 是否删除临时文件
        //private bool deleteTempFile = false;

        public StreamController(ILogger<StreamController> logger, IHttpClientFactory httpClientFactory)
        {
            // 注入logger
            _logger = logger;
            // 注入http client factory
            _httpClientFactory = httpClientFactory;
        }

        // dwg十六进制字符串转换为文件
        // hexString -- 十六进制字符串
        // filename  -- 用户可指定文件名, 也可以不指定
        private string ConvertHexStringToDwgFile(string hexString, string filename = null)
        {
            if (filename == null || filename == "")
            {
                // 在临时文件夹下生成一个随机的dwg文件
                filename = $"{Guid.NewGuid()}.dwg";
            }
            string dwgFile = Path.Combine(Path.GetTempPath(), filename);

            // 将dwg十六进制字符串存储到dwg文件
            byte[] bytes = StringUtil.HexStringToBytes(hexString);
            FileUtil.BytesToFile(bytes, dwgFile);

            return dwgFile;
        }

        // 将dwg文件转化二进制流返回
        // 注: 用于文件下载
        //https://www.cnblogs.com/podolski/p/12682978.html
        //https://www.jianshu.com/p/c076f1298946?tdsourcetag=s_pcqq_aiomsg
        //https://www.cnblogs.com/Martianhh/p/7834078.html
        [HttpPost("download")]
        [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
        //[ProducesResponseType(typeof(ContentResult), StatusCodes.Status200OK)]
        public IActionResult DownloadDwgFile(JObject resource)
        {
            try
            {
                string name = null;
                if (resource.ContainsKey("name") && resource["name"] != null)
                {
                    name = resource["name"].ToObject<string>();
                }
                if (name == null || name == "")
                {
                    name = "未命名";
                }

                string filename = $"{name}.dwg";
                string content = resource["content"].ToObject<string>();
                string dwgFile = this.ConvertHexStringToDwgFile(content, filename);

                if (!System.IO.File.Exists(dwgFile))
                {
                    throw new Exception("无法将stream转换为dwg文件");
                }

                // 方法1: 使用FileContentResult
                //return new FileContentResult(FileUtil.FileToBytes(dwgFile), "application/octet-stream");

                // 方法2: 使用FileStreamResult
                FileStream fs = new FileStream(dwgFile, FileMode.Open);
                FileStreamResult actionresult = new FileStreamResult(fs, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"));
                actionresult.FileDownloadName = filename;
                Response.ContentLength = fs.Length;
                //Response.Headers["Content-Disposition"] = "attachment; filename=" + filename;
                return actionresult;
            }
            catch (Exception e)
            {
                return ApiUtil.Error(e.Message);
            }
        }

        // 接受上传的dwg二进制文件, 并插入预定义的一些图块定义, 返回新的dwg文件
        [HttpPost("upload")]
        //[RequestSizeLimit(30000000)]
        [DisableRequestSizeLimit]
        public IActionResult UploadAndUpdateDwgBlocks([FromForm] string key)
        {
            //// 用户请求blocks.dwg, 返回dwg文件二进制流
            //string content = StringUtil.BytesToHexString(FileUtil.FileToBytes(Path.Combine(DwgService.APP_PATH, "resources/dwg/blocks.dwg")));
            try
            {
                string dwgFile = Path.Combine(Path.GetTempPath(), $"{key}.dwg"); ;
                var files = Request.Form.Files;
                if (files.Count == 0)
                {
                    throw new Exception("未上传dwg文件");
                }
                else
                {
                    // 取出上传的文件
                    IFormFile file = files["file"];
                    //// 将上传的dwg和blocks.dwg合并, 再返回dwg文件二进制流
                    //string content = StringUtil.BytesToHexString(FileUtil.StreamToBytes(file.OpenReadStream()));
                    //return ApiHelper.Ok(string.Format("表单和上传文件测试:key={0}", key), "");

                    // 二进制流另存为dwg文件
                    FileUtil.BytesToFile(FileUtil.StreamToBytes(file.OpenReadStream()), dwgFile);
                }

                if (!System.IO.File.Exists(dwgFile))
                {
                    throw new Exception($"dwg文件不存在:{dwgFile}");
                }

                // 更新块定义
                // 来源: ${webroot}/resources/dwg/blocks.dwg
                DwgService.UpdatePredefinedDwgBlocks(dwgFile);

                // dwg文件转换为十六进制字符串
                string content = StringUtil.BytesToHexString(FileUtil.FileToBytes(dwgFile));
                //if (this.deleteTempFile)
                //{
                //    // 删除文件
                //    System.IO.File.Delete(dwgFile);
                //}

                // 返回
                return ApiUtil.Ok(content);
            }
            catch (Exception e)
            {
                return ApiUtil.Error(e.Message);
            }
        }

        [HttpPost("parse")]
        public IActionResult ParseDwgFile(JObject resource)
        {
            try
            {
                //// 开始计时
                //Stopwatch sw = new Stopwatch();
                //sw.Start();
                string key = resource["key"].ToObject<string>();
                string content = resource["content"].ToObject<string>();
                string dwgFile = this.ConvertHexStringToDwgFile(content, $"{key}.dwg");
                if (!System.IO.File.Exists(dwgFile))
                {
                    throw new Exception("无法将stream转换为dwg文件");
                }

                // 构造一个同名的json文件路径
                string jsonFile = FileUtil.BuildFileNameWithNewExtension(dwgFile, ".json");

                // 解析dwg, 并返回json数据
                // 注: ParseDwgFile函数还有2个可选参数: chunkSize 和 enableGzipCompression
                string res = DwgService.ParseDwgFile(dwgFile, jsonFile);
                //System.IO.File.Delete(dwgFile);
                //System.IO.File.Delete(jsonFile);
                JObject data = (JObject)JsonConvert.DeserializeObject(res);

                //// 停止计时
                //sw.Stop();
                ////耗时ms
                //double ts = sw.ElapsetalSeconds;
                //Console.WriteLine("ParseDwgFile函数耗时: {0}s", ts);

                //// 额外记录函数执行耗时
                // data["timeCost"] = ts;

                // 返回格式
                // {code, msg, data} 
                // https://www.cnblogs.com/erkewang/p/14175420.html
                return ApiUtil.Ok(data);
            }
            catch (Exception e)
            {
                return ApiUtil.Error(e.Message);
            }
        }


        [HttpPost("save")]
        public IActionResult SaveDwgData(JObject resource)
        {
            try
            {
                // 构造一个同名的json文件路径
                string key = resource["key"].ToObject<string>();
                string content = resource["content"].ToObject<string>();
                string dwgFile = this.ConvertHexStringToDwgFile(content, $"{key}.dwg");
                if (!System.IO.File.Exists(dwgFile))
                {
                    throw new Exception("无法将stream转换为dwg文件");
                }

                string jsonFile = FileUtil.BuildFileNameWithNewExtension(dwgFile, ".json");

                // 解析dwg, 并返回json数据
                // 注: ParseDwgFile函数还有2个可选参数: chunkSize 和 enableGzipCompression
                string jsonStr = DwgService.ParseDwgFile(dwgFile, jsonFile);
                //if (this.deleteTempFile)
                //{
                //    System.IO.File.Delete(dwgFile);
                //    System.IO.File.Delete(jsonFile);
                //}
                JObject data = (JObject)JsonConvert.DeserializeObject(jsonStr);

                // 异步发送请求, 将dwg图形数据保存到服务端
                string url = resource["url"].ToObject<string>();
                //string method = resource["method"].ToObject<string>();
                string token = resource["token"].ToObject<string>();
                //string key = resource["key"].ToObject<string>();
                DwgService.SaveDwgData(_httpClientFactory, url, token, key, data);

                return ApiUtil.Ok(null);
            }
            catch (Exception e)
            {
                return ApiUtil.Error(e.Message);
            }
        }

        // 从json中提取自定义图元的数据
        private static JArray GetCustomEntityJson(string jsonStr)
        {
            try
            {
                JObject obj = JObject.Parse(jsonStr);
                if (obj.ContainsKey("customEntities"))
                {
                    return (JArray)obj["customEntities"];
                }
                else
                {
                    return null;
                }
            }
            catch (Exception)
            {
                return null;
            }
        }

        private static string GetValidDwgFile(JObject resource)
        {
            string dwgFile = null;
            if (resource.ContainsKey("dwgFile"))
            {
                // 用户指定了dwgFile字段
                dwgFile = resource["dwgFile"].ToObject<string>();
            }
            else
            {
                // 用户未指定dwgFile字段
                string key = resource["key"].ToObject<string>();
                dwgFile = Path.Combine(Path.GetTempPath(), $"{key}.dwg"); ;
                string emptyDwgFile = Path.Combine(DwgService.APP_PATH, "resources/dwg/empty.dwg");
                // 复制到系统临时文件夹下
                System.IO.File.Copy(emptyDwgFile, dwgFile, true);
            }
            return dwgFile;
        }

        [HttpPost("open")]
        public IActionResult OpenDwgFile(JObject resource)
        {
            try
            {
                string url = resource["url"].ToObject<string>();
                //string method = resource["method"].ToObject<string>();
                string token = resource["token"].ToObject<string>();
                string key = resource["key"].ToObject<string>();

                // 发送请求获取key对应的dwg图形数据
                string jsonStr = DwgService.OpenDwgData(_httpClientFactory, url, token, key);
                if (jsonStr == null || jsonStr == String.Empty)
                {
                    string dwgFile = GetValidDwgFile(resource);
                    // 更新块定义
                    DwgService.UpdatePredefinedDwgBlocks(dwgFile);

                    JObject res = new JObject();
                    // dwg文件 --> 二进制流(byte[]) --> 十六进制字符串
                    res.Add("content", StringUtil.BytesToHexString(FileUtil.FileToBytes(dwgFile)));
                    res.Add("customEntities", null);
                    //if (this.deleteTempFile)
                    //{
                    //    System.IO.File.Delete(dwgFile);
                    //}
                    return ApiUtil.Ok(res);
                }
                else
                {
                    // key对应的图形数据存在
                    JObject res = JObject.Parse(jsonStr);
                    // 服务器返回错误码
                    if (res.ContainsKey("status"))
                    {
                        int statusCode = res["status"].ToObject<int>();
                        if (statusCode < 200 || statusCode >= 300)
                        {
                            if (res.ContainsKey("message"))
                            {
                                throw new Exception(res["message"].ToObject<string>());
                            }
                        }
                    }

                    // 构造一个同名的json文件路径
                    string dwgFile = GetValidDwgFile(resource);
                    string jsonFile = FileUtil.BuildFileNameWithNewExtension(dwgFile, ".json");

                    // 写入到json文件
                    System.IO.File.WriteAllText(jsonFile, jsonStr);


                    // 读取json文件, 覆盖或生成新的dwg文件
                    // 例如: c:/tets.dwg ==> c:/test_new.dwg
                    string newDwgFile = DwgService.MakeDwgFile(dwgFile, jsonFile, null);

                    // 更新块定义
                    DwgService.UpdatePredefinedDwgBlocks(newDwgFile);

                    // 构造返回结果
                    // data: {content: xxx,  customEntities: xxx}
                    res.RemoveAll();
                    res.Add("content", StringUtil.BytesToHexString(FileUtil.FileToBytes(newDwgFile)));
                    res.Add("customEntities", GetCustomEntityJson(jsonStr));
                    //if (this.deleteTempFile)
                    //{
                    //    System.IO.File.Delete(newDwgFile);
                    //    System.IO.File.Delete(jsonFile);
                    //}
                    return ApiUtil.Ok(res);
                }
            }
            catch (Exception e)
            {
                return ApiUtil.Error(e.Message);
            }
        }
    }
}
